package cn.swust.designpatternlearningplatform.service.impl;

import cn.swust.designpatternlearningplatform.dao.*;
import cn.swust.designpatternlearningplatform.domain.bo.OptionsBo;
import cn.swust.designpatternlearningplatform.domain.bo.TopicDifficultyBo;
import cn.swust.designpatternlearningplatform.domain.bo.TrainingTopicBo;
import cn.swust.designpatternlearningplatform.domain.dto.PaperResultDto;
import cn.swust.designpatternlearningplatform.domain.dto.TestPaperDto;
import cn.swust.designpatternlearningplatform.domain.dto.StudentPersonalTrainingPaperDto;
import cn.swust.designpatternlearningplatform.domain.dto.StudentPersonalTrainingResultDto;
import cn.swust.designpatternlearningplatform.domain.entity.PaperResult;
import cn.swust.designpatternlearningplatform.domain.entity.Topic;
import cn.swust.designpatternlearningplatform.domain.entity.TrainingPaper;
import cn.swust.designpatternlearningplatform.service.StudentTrainingPaperService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StudentTrainingPaperServiceImpl implements StudentTrainingPaperService {
    @Resource
    private StudentTrainingPaperDao studentTrainingPaperDao;
    @Resource
    private TopicDao topicDao;
    @Resource
    private TopicOptionDao topicOptionDao;

    @Resource
    private TestPaperContentDao testPaperContentDao;

    @Resource
    PaperResultDao paperResultDao;

    @Override
    public TestPaperDto selectTrainingPaper(String testId, String number) {
        List<Integer> topicId = studentTrainingPaperDao.getTrainingPaperTopicId(testId, number);
        List<Topic> topicList = new ArrayList<>();
        for (int i = 0; i < topicId.size(); i++) {
            Topic topic = topicDao.selectTopicById(topicId.get(i));
            topicList.add(topic);
        }
        List<TrainingTopicBo> trainingTopicBoList = new ArrayList<>();
        for (int i = 0; i < topicList.size(); i++) {
            Topic topic = topicList.get(i);
            List<OptionsBo> list3 = topicOptionDao.getTopicOptions(topic.getTopicId());
            TrainingTopicBo trainingTopicBo = new TrainingTopicBo();
            trainingTopicBo.setTopicId(topic.getTopicId());
            trainingTopicBo.setTopicType(topic.getTopicType());
            trainingTopicBo.setTopicDifficulty(topic.getTopicDifficulty());
            trainingTopicBo.setTopicContent(topic.getTopicContent());
            trainingTopicBo.setTopicContentPath(topic.getTopicContentPath());
            trainingTopicBo.setOptions(list3);
            trainingTopicBoList.add(trainingTopicBo);
        }
        TestPaperDto testPaperDto = new TestPaperDto();
        testPaperDto.setPaperNumber(testId);
        testPaperDto.setTrainingTopicBoList(trainingTopicBoList);
        return testPaperDto;
    }

    @Override
    @Transactional
    public TestPaperDto getTrainingPaperByNumber(Integer trainingNumber, String paperName, String studentNumber) {
        String uuid = UUID.randomUUID().toString();
        TrainingPaper trainingPaper = new TrainingPaper();
        trainingPaper.setPaperName(paperName);
        trainingPaper.setPaperNumber(uuid);
        trainingPaper.setStudentNumber(studentNumber);
        studentTrainingPaperDao.insertTrainingPaper(trainingPaper);
        List<TopicDifficultyBo> list1 = topicDao.getTopicAndDifficulty();
        List<TopicDifficultyBo> list = new ArrayList<>();

        for (int i = 0; i < list1.size(); i++) {
            if (list1.get(i).getTopicDifficulty() != null) {
                list.add(list1.get(i));
            }
        }
        int listSize = list.size();
        Map<String, List<Integer>> collect = list.stream().collect(Collectors.groupingBy(TopicDifficultyBo::getTopicDifficulty, Collectors.mapping(TopicDifficultyBo::getTopicId, Collectors.toList())));
        List<TrainingTopicBo> trainingTopicBoList = new ArrayList<>();
        if (listSize <= trainingNumber) {
            List<Topic> list2 = topicDao.getAllTopic();
            for (int i = 0; i < list2.size(); i++) {
                Topic topic = list2.get(i);
                studentTrainingPaperDao.addPaperInformation(topic.getTopicId(), uuid, studentNumber);
                List<OptionsBo> list3 = topicOptionDao.getTopicOptions(topic.getTopicId());
                TrainingTopicBo trainingTopicBo = new TrainingTopicBo();
                trainingTopicBo.setTopicId(topic.getTopicId());
                trainingTopicBo.setTopicType(topic.getTopicType());
                trainingTopicBo.setTopicDifficulty(topic.getTopicDifficulty());
                trainingTopicBo.setTopicContent(topic.getTopicContent());
                trainingTopicBo.setTopicContentPath(topic.getTopicContentPath());
                trainingTopicBo.setOptions(list3);
                trainingTopicBoList.add(trainingTopicBo);
            }
            TestPaperDto testPaperDto = new TestPaperDto();
            testPaperDto.setPaperNumber(uuid);
            testPaperDto.setTrainingTopicBoList(trainingTopicBoList);
            return testPaperDto;
        } else {
            int easy = (int) (trainingNumber * 0.3);
            int middle = (int) (trainingNumber * 0.4);
            int difficult = (int) (trainingNumber * 0.3);
            if (easy + middle + difficult + 1 == trainingNumber) {
                middle = middle + 1;
            } else if (easy + middle + difficult + 2 == trainingNumber) {
                easy = easy + 1;
                difficult = difficult + 1;
            }
            Random random = new Random();
            //按照三种题目的数量进行排序
            LinkedHashMap<String, List<Integer>> collect1 = collect.entrySet().stream().sorted(Comparator.comparingInt(s -> s.getValue().size())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                    (oldValue, newValue) -> oldValue, LinkedHashMap::new));
            int flag = 0;
            Set<Integer> topicId = new HashSet<>();
            for (Map.Entry<String, List<Integer>> entry : collect1.entrySet()) {
                List<Integer> list2 = entry.getValue();
                String typeName = entry.getKey();
                if (typeName.equals("简单")) {
                    if (list2.size() > flag + easy) {
                        for (int i = 0; i < flag + easy; i++) {
                            int size = topicId.size();
                            do {
                                topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                            } while (topicId.size() == size);
                        }
                        flag = 0;
                    } else {
                        for (int i = 0; i < list2.size(); i++) {
                            int size = topicId.size();
                            do {
                                topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                            } while (topicId.size() == size);
                        }
                        flag = flag - list2.size() + easy;
                    }
                } else if (typeName.equals("中等")) {
                    if (list2.size() > flag + middle) {
                        for (int i = 0; i < flag + middle; i++) {
                            int size = topicId.size();
                            do {
                                topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                            } while (topicId.size() == size);
                        }
                        flag = 0;
                    } else {
                        for (int i = 0; i < list2.size(); i++) {
                            int size = topicId.size();
                            do {
                                topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                            } while (topicId.size() == size);
                        }
                        flag = flag - list2.size() + middle;
                    }

                } else {
                    if (typeName.equals("困难")) {
                        if (list2.size() > flag + difficult) {
                            for (int i = 0; i < flag + difficult; i++) {
                                int size = topicId.size();
                                do {
                                    topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                                } while (topicId.size() == size);
                            }
                            flag = 0;
                        } else {
                            for (int i = 0; i < list2.size(); i++) {
                                int size = topicId.size();
                                do {
                                    topicId.add(list2.get(random.nextInt(list2.size() - 1)));
                                } while (topicId.size() == size);
                            }
                            flag = flag - list2.size() + difficult;
                        }

                    }
                }
            }

            for (Integer i : topicId) {
                studentTrainingPaperDao.addPaperInformation(i, uuid, studentNumber);
                Topic topic = topicDao.selectTopicById(i);
                List<OptionsBo> list3 = topicOptionDao.getTopicOptions(topic.getTopicId());
                TrainingTopicBo trainingTopicBo = new TrainingTopicBo();
                trainingTopicBo.setTopicId(topic.getTopicId());
                trainingTopicBo.setTopicType(topic.getTopicType());
                trainingTopicBo.setTopicDifficulty(topic.getTopicDifficulty());
                trainingTopicBo.setTopicContent(topic.getTopicContent());
                trainingTopicBo.setTopicContentPath(topic.getTopicContentPath());
                trainingTopicBo.setOptions(list3);
                trainingTopicBoList.add(trainingTopicBo);
            }
            TestPaperDto testPaperDto = new TestPaperDto();
            testPaperDto.setPaperNumber(uuid);
            testPaperDto.setTrainingTopicBoList(trainingTopicBoList);
            return testPaperDto;
        }
    }

    @Override
    @Transactional
    public List<StudentPersonalTrainingPaperDto> getAllTrainingPaper(String studentNumber) {
        List<StudentPersonalTrainingPaperDto> list = studentTrainingPaperDao.getAllTrainingPaper(studentNumber);
        log.info(list.toString());
        return list;
    }

    /**
     * @param paperNumber:
     * @return List<StudentPersonalTrainingResultDto>
     * @author wang
     * description 获取学生的试卷的详细情况，自己的答案以及试题解析
     * date 2023/5/9 16:40
     */
    @Override
    public PaperResultDto getStudentPersonalTraining(String paperNumber, String studentNumber) {
        List<Integer> topicId = studentTrainingPaperDao.getTopicId(paperNumber, studentNumber);
        Integer count = topicId.size();
        count = 100 / count;
        Integer total = 0;
        List<StudentPersonalTrainingResultDto> studentPersonalTrainingResultDtos = new ArrayList<>();
        for (int i = 0; i < topicId.size(); i++) {
            Topic topic = topicDao.selectTopicById(topicId.get(i));
            List<OptionsBo> options = topicOptionDao.getTopicOptions(topicId.get(i));
            StudentPersonalTrainingResultDto s = new StudentPersonalTrainingResultDto();
            s.setTopicContent(topic.getTopicContent());
            s.setTopicContentPath(topic.getTopicContentPath());
            s.setOptions(options);
            s.setTopicAnalyse(topic.getTopicAnalyse());
            s.setTopicAnalysePath(topic.getTopicAnalysePath());
            s.setRightAnswer(topic.getTopicAnswer());
            String ownAnswer = studentTrainingPaperDao.getOwnAnswer(paperNumber, topicId.get(i), studentNumber);
            s.setOwnAnswer(ownAnswer);
            if (Objects.equals(s.getRightAnswer(), s.getOwnAnswer())) {
                total = total + count;
            }
            studentPersonalTrainingResultDtos.add(s);
        }
        PaperResultDto paperResultDto = new PaperResultDto();
        paperResultDto.setList(studentPersonalTrainingResultDtos);
        paperResultDto.setTotal(total);
        return paperResultDto;
    }

    @Override
    public PaperResultDto getTestPaperResult(String paperNumber, String studentNumber) {
        List<Integer> topicId = testPaperContentDao.selecteTestPaper(paperNumber);
        int count = topicId.size();
        count = 100 / count;
        int total = 0;
        List<PaperResult> paperResult = paperResultDao.getPaperResult(studentNumber, paperNumber);
        Map<Integer, String> collect = paperResult.stream().collect(Collectors.toMap(PaperResult::getTopicId, PaperResult::getOwnAnswer, (existingValue, newValue) -> newValue));
        List<StudentPersonalTrainingResultDto> studentPersonalTrainingResultDtos = new ArrayList<>();
        for (Integer integer : topicId) {
            Topic topic = topicDao.selectTopicById(integer);
            if (topic == null) {
                continue;
            }
            List<OptionsBo> options = topicOptionDao.getTopicOptions(integer);
            StudentPersonalTrainingResultDto s = new StudentPersonalTrainingResultDto();
            s.setTopicContent(topic.getTopicContent());
            s.setTopicContentPath(topic.getTopicContentPath());
            s.setOptions(options);
            s.setTopicAnalyse(topic.getTopicAnalyse());
            s.setTopicAnalysePath(topic.getTopicAnalysePath());
            s.setRightAnswer(topic.getTopicAnswer());
            s.setOwnAnswer(collect.get(topic.getTopicId()));
            if (Objects.equals(s.getRightAnswer(), s.getOwnAnswer())) {
                total = total + count;
            }
            studentPersonalTrainingResultDtos.add(s);
        }
        PaperResultDto paperResultDto = new PaperResultDto();
        paperResultDto.setList(studentPersonalTrainingResultDtos);
        paperResultDto.setTotal(total);
        return paperResultDto;
    }
}
